import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame; 
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.picking.*;
import javax.media.j3d.TransparencyAttributes;
import java.lang.Object;
import javax.media.j3d.SceneGraphObject;
import javax.media.j3d.NodeComponent;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.event.*;
import java.util.Enumeration;

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.Random;
import javax.swing.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.lang.System;
import java.awt.DisplayMode;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GraphicsConfiguration;
import java.awt.Window;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;
import java.io.*;
import java.net.*;
import java.lang.Object;

import javax.media.j3d.ImageComponent;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.Raster;

import java.util.Scanner;



 
public class Main extends Applet implements MouseListener, MouseMotionListener
{
	
	private PickCanvas pickCanvas;
	
	Color3f green = new Color3f(Color.green);
    Color3f blue = new Color3f(Color.blue);
    Color3f orange = new Color3f(Color.orange);
    Color3f magenta = new Color3f(Color.magenta);
    Color3f black = new Color3f(Color.black);
    Color3f white = new Color3f(Color.white);
    
    Game game;
    
    char screen;
 
 	BranchGroup scene;
 
    public Main()throws IOException
    {
    	char[] gT = new char[6];
    	
    	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	
    	System.out.println("Othello - Steven & Nic");
    	System.out.println("----------------------");
    	System.out.println("\n\tPlayer v Player: p");
    	System.out.println("\tPlayer v Comp:\t v");
    	System.out.println("\tComp v Comp:\t c");    	
    	System.out.print("Enter type of game(p, v, c): ");
    	gT[0] = (br.readLine()).charAt(0);
    	
    	System.out.println("\n\t6 x 6:\t\ts");
    	System.out.println("\t8 x 8:\t\tm");
    	System.out.println("\t12 x 12:\tl");
    	System.out.println("\t16 x 16:\tt");
    	System.out.println("\t6 x 6 x 6:\tS");  
    	System.out.println("\t8 x 8 x 8:\tM");
    	System.out.println("\t12 x 12 x 12:\tL");  
    	System.out.println("\t16 x 16 x 16:\tT");   	
    	System.out.print("Enter size of board(s, m, l, t, S, M, L, T): ");
    	gT[3] = (br.readLine()).charAt(0);
    	
    	System.out.println("\n\tMayonnaise\tm");
    	System.out.println("\tHotDog\t\th");
    	System.out.println("\tFlower\t\tf");
    	System.out.println("\tPirate\t\tp");
    	System.out.println("\tNinja\t\tn");  
    	System.out.println("\tVin Diesel\tv");
    	System.out.println("\tChuck Norris\tc");  
    	System.out.println("\tDr. Keyser\tk");   	
    	System.out.print("Enter player one person(m, h, f, p, n, v, c, k): ");
    	gT[1] = (br.readLine()).charAt(0);
    	System.out.print("Enter player two person(m, h, f, p, n, v, c, k): ");
    	gT[2] = (br.readLine()).charAt(0);
    	   	
    	System.out.print("\nHelp on(y , n): ");
    	gT[4] = (br.readLine()).charAt(0);
    	
    	System.out.print("Play to lose(y, n): ");
    	gT[5] = (br.readLine()).charAt(0);
    	
       	game = new Game(gT, this);
      	 
       	checkCursor();
                     
	       setLayout(new BorderLayout());
	       GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
	 
	       Canvas3D canvas3D = new Canvas3D(config);
	       add("Center", canvas3D);
	 		 
	       scene = createSceneGraph();
	 
	       SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
	 
		   simpleU.getViewingPlatform().setNominalViewingTransform();
	 
	       simpleU.addBranchGraph(scene);
	       
	       pickCanvas = new PickCanvas(canvas3D, scene);
		   
		   pickCanvas.setMode(PickCanvas.GEOMETRY);
	
	       canvas3D.addMouseListener(this);
	       canvas3D.addMouseMotionListener(this);
	       
	   updateSpheres();
    }
 
    public static void main(String[] args)throws IOException
    {
    	
       Frame frame = new MainFrame(new Main(), 800, 600);    
    }    
    
    public BranchGroup createSceneGraph()
    {
    	BranchGroup objRoot = new BranchGroup();
    
    				     
	        TransformGroup objTransform = new TransformGroup();
	        objTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	        objTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
	 
	 		objRoot.addChild(objTransform);
	 		
	 		BoundingSphere boundingSphere = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
	   		Background background = new Background(white);    
	    	background.setApplicationBounds(boundingSphere);
	    		    	
	 		if(game.board.zSize == 1)
	 		{
	 			double od = 1.4 / game.board.size;
	 			
	 			float off = new Float(od);
	 				 			
	 			int i = 0; 		
		        for (float x = -0.7f; x <= 0.7f && i < game.board.size; x = x + off, i++)
			    {	
			    	int j = 0;
				    for (float y = -0.7f; y <= 0.7f && j < game.board.size; y = y + off, j++)
				    {	
				    	int k = 0;			    	
					    Appearance ap = new Appearance();
					    ap.setCapability(Appearance.ALLOW_MATERIAL_READ);
		            	ap.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
		            	ap.setCapability(Material.ALLOW_COMPONENT_WRITE);
					        
					    ap.setMaterial(new Material(black, black, black, black, 2.0f));
										      	  	
						int primflags = Primitive.GENERATE_NORMALS + Primitive.GENERATE_TEXTURE_COORDS + Primitive.GEOMETRY_NOT_SHARED + Primitive.ENABLE_APPEARANCE_MODIFY;
						  			
				  		Sphere sphere = new Sphere(0.03f, primflags, ap);	
						TransformGroup tg = new TransformGroup();	
					    Transform3D transform = new Transform3D();	
					    Vector3f vector = new Vector3f( x, y, 0.0f);	
					    transform.setTranslation(vector);
					      
					    sphere.setCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE);
					    sphere.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);
					    sphere.setName((char)i+" "+(char)j+" "+(char)k+" ");
					    tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);		      	
					    tg.setTransform(transform);	
					    tg.addChild(sphere);	
					    objTransform.addChild(tg);
				    }
			   	}	 			
	 		}	 		
	 		else
	 		{
	 			double od = 1.4 / game.board.size;	 			
	 			
	 			float off = new Float(od);
	 			 				 			
	 			int i = 0; 		
		        for (float x = -0.7f; x <= 0.7f && i < game.board.size; x = x + off, i++)
			    {	
			    	int j = 0;
				    for (float y = -0.7f; y <= 0.7f && j < game.board.size; y = y + off, j++)
				    {
				    	int k = 0;
				    	for (float z = -0.7f; z <= 0.7f && k < game.board.size; z = z + off, k++)
				   		{
					        Appearance ap = new Appearance();
					        ap.setCapability(Appearance.ALLOW_MATERIAL_READ);
		            		ap.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
		            		ap.setCapability(Material.ALLOW_COMPONENT_WRITE);
					        
					       	ap.setMaterial(new Material(black, black, black, black, 2.0f));
						   
						   	//	ap.setMaterial(new Material(orange, black, orange, black, 2.0f));
						   	
				      	  	
						 	int primflags = Primitive.GENERATE_NORMALS + Primitive.GENERATE_TEXTURE_COORDS + Primitive.GEOMETRY_NOT_SHARED + Primitive.ENABLE_APPEARANCE_MODIFY;
						  			
				  			Sphere sphere = new Sphere(0.03f, primflags, ap);	
						    TransformGroup tg = new TransformGroup();	
					     	Transform3D transform = new Transform3D();	
					      	Vector3f vector = new Vector3f( x, y, z);	
					      	transform.setTranslation(vector);
					      
					      	sphere.setCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE);
					      	sphere.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);
					      	sphere.setName((char)i+" "+(char)j+" "+(char)k+" ");
					      	tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);		      	
					      	tg.setTransform(transform);	
					      	tg.addChild(sphere);	
					      	objTransform.addChild(tg);
				    	}
				    }
			   	}
			}
	 
	       	MouseRotate myMouseRotate = new MouseRotate();
	       	myMouseRotate.setTransformGroup(objTransform);
	       	myMouseRotate.setSchedulingBounds(new BoundingSphere());
	       	objRoot.addChild(myMouseRotate);
	  
	       	MouseWheelZoom myMouseZoom = new MouseWheelZoom();
	       	myMouseZoom.setTransformGroup(objTransform);
	       	myMouseZoom.setSchedulingBounds(new BoundingSphere());
	       	objRoot.addChild(myMouseZoom);
	        
	       	BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
		
		   	Vector3f lightDirection = new Vector3f(4.0f, -7.0f, -12.0f);
		
		   	DirectionalLight light = new DirectionalLight(white, lightDirection);
		
		   	light.setInfluencingBounds(bounds);
		
		   	objRoot.addChild(light);
		   
		   	objRoot.addChild(background);
		   
		   /*
		   	Pic[] pics = game.getPics();
		   	
		   	for(int i = 0; i < 5; i++)
		   	{
		   		int w = 0;
		   		int h = 0;
		   		
		   		float xf = 0.0f;
		   		float yf = 0.0f;
		   		
		   		switch(i)
		   		{
		   			case 0: w = 100;
		   					h = 50;
		   					xf = 0.0f;
		   					yf = 0.0f;
		   					break;
		   			case 1: w = 196;
		   					h = 53;
		   					xf = 0.0f;
		   					yf = 0.0f;
		   					break;
		   			case 2: w = 129;
		   					h = 53;
		   					xf = 0.0f;
		   					yf = 0.0f;
		   					break;
		   			case 3: w = 180;
		   					h = 56;
		   					xf = 0.0f;
		   					yf = 0.0f;
		   					break;
		   			case 4: w = 150;
		   					h = 200;
		   					xf = -0.999f;
		   					yf = 0.75f;
		   					break;
		   			case 5: w = 150;
		   					h = 200;
		   					xf = -0.625f;
		   					yf = 0.75f;
		   					break;
		   					
		   		}
		   		
			   	BufferedImage pic = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
				
			   	Graphics gb = pic.createGraphics();
			   
			   	Image p = pics[i].image;
		        			
		       	gb.drawImage(p, 0, 0, null);
		       	
		       	if(i == 4)
		       	{
		       		p = pics[6].image;
		        			
		       		gb.drawImage(p, 5, 5, null);
		       	}
		       	if(i == 5)
		       	{
		       		p = pics[7].image;
		        			
		       		gb.drawImage(p, 5, 5, null);
		       	}
		       	   
			   	ImageComponent2D image = new ImageComponent2D(ImageComponent2D.FORMAT_RGBA8, pic);
			   
				Raster drawRaster = new Raster(new Point3f(xf, yf, 0.0f),Raster.RASTER_COLOR, 0, 0, w, h, image, null);
		    	Shape3D shape = new Shape3D(drawRaster);
		    	drawRaster.setCapability(Raster.ALLOW_IMAGE_WRITE);
		    	objRoot.addChild(shape);
		    			    	

		    }*/
		           	
	        
	    objRoot.compile();
	 
		return objRoot;
    }
    
    public void updateSpheres()
    {
    	Enumeration e = scene.getAllChildren();
    	
    	Enumeration i = ((TransformGroup)((Node)e.nextElement())).getAllChildren();
    	
    	while(i.hasMoreElements())
    	{	
    			Enumeration j = ((TransformGroup)((Node)i.nextElement())).getAllChildren();
	    		while(j.hasMoreElements())
	    		{
	    			Primitive p = (Primitive)((Node)j.nextElement());
	    			Appearance ap = new Appearance();
	    			    			    			
	    			int[] cords = new int[3];
			   		cords[0] = (int)((char)p.getName().charAt(0));
			   		cords[1] = (int)((char)p.getName().charAt(2));
			   		cords[2] = (int)((char)p.getName().charAt(4));
			   		
			   		//System.out.println(p.getName());
			   		
			   		//System.out.println(cords[0]+" "+cords[1]+" "+cords[2]);
	    			
	    			if(game.board.boardAt(cords[0], cords[1], cords[2]) == 'o')
	    			{
	    				TransparencyAttributes t_attr = new TransparencyAttributes(TransparencyAttributes.BLENDED,0.6f);
						ap.setTransparencyAttributes( t_attr ); 
	    				ap.setMaterial(new Material(magenta, black, magenta, black, 2.0f));
	    			}
	    			else if(game.board.boardAt(cords[0], cords[1], cords[2]) == 'x')
	    			{
	    				TransparencyAttributes t_attr = new TransparencyAttributes(TransparencyAttributes.BLENDED,0.6f);
						ap.setTransparencyAttributes( t_attr ); 
	    				ap.setMaterial(new Material(orange, black, orange, black, 2.0f));
	    			}
	    			else if(game.board.boardAt(cords[0], cords[1], cords[2]) == 'g')
	    				ap.setMaterial(new Material(green, black, green, black, 2.0f));
	    			else if(game.board.boardAt(cords[0], cords[1], cords[2]) == 'b')
	    				ap.setMaterial(new Material(blue, black, blue, black, 2.0f));
	    			    				
	    			p.setAppearance(ap);    			
	    		}    		
	    	
	    }
    }
    
    public void mouseMoved(MouseEvent e)//Method to dectect which sphere yer mouse is over, runs too slow tho
    {   
		int mX = e.getX();
		int mY = e.getY();
		
		game.mouseMove(mX, mY);
    	
    	e.consume();   
    }
    
    public void mouseClicked(MouseEvent e)
	{	
		int mX = e.getX();
		int mY = e.getY();
		
	  	    pickCanvas.setShapeLocation(e);	
		    PickResult result = pickCanvas.pickClosest();
		
		    if(result != null)
		    {	    	
		       Primitive p = (Primitive)result.getNode(PickResult.PRIMITIVE);	
		       if (p != null)
			   {
			   		int[] cords = new int[3];
			   		cords[0] = (int)(p.getName().charAt(0));
			   		cords[1] = (int)(p.getName().charAt(2));
			   		cords[2] = (int)(p.getName().charAt(4));
			   		
			   		//System.out.println(cords[0]+" "+cords[1]+" "+cords[2]);
			   		
			   		if(game.gameType[0] == 'p' || (game.gameType[0] == 'v' && game.turn == 1))
			   			game.attemptMove(cords);
			   		
			   		checkCursor();
			   	}
		    }
		    
		    if(game.gameType[0] == 'c')
		    	game.AITurn();
		    	
		    //game.click(mX,mY);
		    	
		    updateSpheres();  
				    	
    	e.consume();  
	}
	
	public void mouseReleased(MouseEvent e){ e.consume(); }
	
	public void mouseExited(MouseEvent e){ e.consume(); }
	
	public void mouseEntered(MouseEvent e){ e.consume(); }
	
	public void mousePressed(MouseEvent e){ e.consume(); }
	
	public void mouseDragged(MouseEvent e){ e.consume(); }
	
	public Point3f toPoint3f(int x, int y)
	{
		double dx = (x - 400) / 400;
		double dy = ((y + 100) - 400) / 400;
		
		if(dx == -1.0)
			dx = -0.999f;
			
		
		Point3f p = new Point3f(new Float(dx), new Float(dy), 0.0f);
		
		return p;
	}
	
	public void checkCursor()
	{
		if(game.turn == 1)
		{
			Image cursorPic = getToolkit().getImage("Menu\\greenCursor.gif");
			Cursor cursor = getToolkit().createCustomCursor(cursorPic, new Point(), "Steve");
			this.setCursor(cursor);
		}
		else
		{
			Image cursorPic = getToolkit().getImage("Menu\\blueCursor.gif");
			Cursor cursor = getToolkit().createCustomCursor(cursorPic, new Point(), "Steve");
			this.setCursor(cursor);
		}
	}
		
}
